from manimlib import *
from numpy import blackman

class Deck(Group):

    def __init__(self, radius=2,height=0.2,num=1,color=[BLUE_B,WHITE]):
        self.radius=radius
        self.num=num
        self.color=color
        self.random_angle=random.uniform(0,2*PI)
        super().__init__()
        self.add(Cylinder(radius=self.radius,height=height,color=self.color[0],opacity=1).shift(height/2*IN))
        self.add(*self.get_anulus())
        self.add(*self.get_sides())
        self.add(Integer(num).set_color(BLACK).scale(radius))
        self.move_to(ORIGIN)
    def get_anulus(self):
        a = Circle(radius=self.radius,stroke_width=0,fill_color=self.color[1],fill_opacity=1)
        b = Circle(radius=self.radius*0.7,stroke_width=0,fill_color=self.color[0],fill_opacity=1)
        c = Circle(radius=self.radius*0.6,stroke_width=0,fill_color=WHITE,fill_opacity=1)
        return [a,b,c]
    
    def get_sides(self):
        start = AnnularSector(outer_radius=self.radius,inner_radius=self.radius*0.8,start_angle=random.uniform(0,2*PI),angle=PI/6,fill_color=self.color[0],fill_opacity=1,stroke_width=0)
        return Group(*[start.copy().rotate_about_origin(PI/3*i) for i in range(6)])

def plus(num):
    if num>0:
        color=[BLUE_A,BLUE]
    if num<0:
        color=[ORANGE,RED]
    vgs = Group(*[Deck(num=np.sign(num)*1,color=color,height=0.4).shift(np.array([random.uniform(-0.1,0.1),random.uniform(-0.1,0.1),i])) for i in np.linspace(-2,2,abs(num))])
    vgs.move_to(ORIGIN).rotate(-40*DEGREES,axis=RIGHT)
    return vgs
class test(ThreeDScene):
    def construct(self):
        vgs = plus(-4)

        self.add(vgs)
# quiz
class quiz(Scene):
    def construct(self):
        pics = Group(ImageMobject("gauss"),ImageMobject("turing"),ImageMobject("von"),ImageMobject("shanon")).arrange_in_grid(2,2).set_height(6)
        abcs = VGroup(*[Tex("\mathrm "+i).set_color(BLACK).next_to(j,DOWN) for i,j in zip(["A","B","C","D"],pics)])
        self.wait(2)
        self.play(LaggedStart(*[FadeIn(a,shift=UP) for a in pics]),LaggedStart(*[FadeIn(a,shift=UP) for a in abcs]))
        self.wait(4)


# PART1
class PART1(Scene):
    def construct(self):
        title = TexText("囚徒困境").scale(2).to_edge(UP).set_color(BLACK)
        squ = Polygon(UP,RIGHT*2+DOWN,DOWN*3,LEFT*2+DOWN,stroke_width=5,stroke_color=BLACK)
        line1 = Line(RIGHT,LEFT+DOWN*2,stroke_width=3,stroke_color=BLACK)
        line2 = Line(LEFT,RIGHT+DOWN*2,stroke_width=3,stroke_color=BLACK)
        silent = VGroup(
            TexText("沉默").move_to(np.array([-0.7,0.7,0])).rotate(45*DEGREES).set_color(RED),
            TexText("沉默").move_to(np.array([0.7,0.7,0])).rotate(-45*DEGREES).set_color(RED),
        )
        complain = VGroup(
            TexText("坦白").move_to(np.array([-1.7,-0.3,0])).rotate(45*DEGREES).set_color(GREEN),
            TexText("坦白").move_to(np.array([1.7,-0.3,0])).rotate(-45*DEGREES).set_color(GREEN).insert_n_curves(20),
        )
        little1 = Line(UP,DOWN,stroke_width=1,stroke_color=BLACK)
        little2 = Line(LEFT,LEFT+DOWN*2,stroke_width=1,stroke_color=BLACK)
        little3 = Line(RIGHT,RIGHT+DOWN*2,stroke_width=1,stroke_color=BLACK)
        little4 = Line(DOWN,DOWN*3,stroke_width=1,stroke_color=BLACK)
        self.play(Write(title))
        self.wait(3)
        self.play(FadeOut(title))
        self.wait(2)
        self.play(ShowCreation(squ))
        self.wait(5)
        self.play(ShowCreation(line1),ShowCreation(line2),Write(silent[0]),Write(silent[1]),Write(complain[0]),Write(complain[1]))
        self.wait()
        SS = VGroup(
            Tex("1").next_to(little1,LEFT).set_color(RED),
            Tex("1").next_to(little1).set_color(RED),
        )
        CS = VGroup(
            Tex("0").next_to(little2,LEFT).set_color(GREEN),
            Tex("8").next_to(little2).set_color(RED),
        )
        SC = VGroup(
            Tex("8").next_to(little3,LEFT).set_color(RED),
            Tex("0").next_to(little3).set_color(GREEN),
        )
        CC = VGroup(
            Tex("5").next_to(little4,LEFT).set_color(GREEN),
            Tex("5").next_to(little4).set_color(GREEN),
        )
        self.play(Write(SS[0]),Write(SS[1]),ShowCreation(little1))
        self.wait(2)
        self.play(Write(CS[0]),Write(CS[1]),ShowCreation(little2))
        self.wait(2)
        self.play(Write(SC[0]),Write(SC[1]),ShowCreation(little3))
        self.wait(2)
        self.play(Write(CC[0]),Write(CC[1]),ShowCreation(little4))
        self.wait(5)
        # 如果乙选择坦白，你应该选择？（互动点）坦白
        self.play(CS.animate.set_opacity(0.1),SS.animate.set_opacity(0.1))
        self.wait(5)
        # 如果乙选择沉默，你应该选择？（互动点）坦白
        self.play(CS.animate.set_opacity(1),SS.animate.set_opacity(1),SC.animate.set_opacity(0.1),CC.animate.set_opacity(0.1))
        self.wait(5)
        # ababs
        self.play(SC.animate.set_opacity(1),CC.animate.set_opacity(1))
        self.wait(3)
        self.play(Indicate(CC[0]),Indicate(CC[1]))
        self.wait()
        self.play(Indicate(SS[0]),Indicate(SS[1]))
        self.wait(3)
        self.play(FadeOut(VGroup(*self.mobjects)))


class PART2(Scene):
    def construct(self):
        A = np.array([2.8380111763,2.3332661303,0])
        B = np.array([0.6505326253,-1.0547149114,0])
        C = np.array([4.596687192,-1.3717919431,0])
        cross_on_A = Cross(Square(1.25).move_to(A))
        cross_on_B = Cross(Square(1.25).move_to(B))
        cross_on_C = Cross(Square(1.25).move_to(C))
        circle_on_A = Circle(radius=1).set_color(RED).move_to(A)
        circle_on_B = Circle(radius=1).set_color(RED).move_to(B)
        circle_on_C = Circle(radius=1).set_color(RED).move_to(C)
        cross = {"A":cross_on_A,"B":cross_on_B,"C":cross_on_C}
        circle = {"A":circle_on_A,"B":circle_on_B,"C":circle_on_C}

        def Beat(p1, p2, fade_cross=False, success=True, animation=FadeOut(Dot(UP*10))):
            self.play(ShowCreation(circle[p1]))
            self.wait(.5)
            if success:
                self.play(ReplacementTransform(VGroup(circle[p1].copy(),circle[p1].copy()),cross[p2]))
                if fade_cross:
                    self.play(FadeOut(cross[p2]),FadeOut(circle[p1]),animation)
                else:
                    self.play(FadeOut(circle[p1]),animation)
            else:
                m = VGroup(circle[p1].copy(),circle[p1].copy())
                self.play(Transform(m,cross[p2]),rate_func=lambda t:there_and_back(t)*0.8,run_time=2)
                self.remove(m)
                self.play(FadeOut(circle[p1]),animation)

        Q1 = TexText("假如轮到丙开枪的时候三人都存活，丙该怎么办？")
        Q2 = TexText("假如轮到乙开枪的时候三人都存活，乙该怎么办？")
        Q3 = TexText("甲最先开枪，应该怎么做？")
        Qlist = VGroup(Q1,Q2,Q3).scale(.5).arrange(DOWN,buff=1).to_edge(LEFT).set_color(BLACK)
        Q3.align_to(Q1,LEFT)
        title = TexText("枪手决斗模型").scale(2).to_edge(UP,buff=0.5).set_color(BLACK)
        self.play(Write(title))
        #枪手决斗模型
        self.wait(3)
        self.play(FadeOut(title))
        # 有三个枪手甲、乙、丙正在三座呈等边三角形的山头上决斗。甲的命中率是30%，乙的命中率是60%，丙的命中率是100%。
        # 它们规定以甲、乙、丙的顺序轮流开一枪，直至只剩一人存活为止。假定：每个人都想尽可能地生还，不存在拉帮结派。
        self.wait(30)
        #self.wait(5)
        self.play(Write(Q1))
        #假如轮到丙开枪的时候三人都存活，丙应该打谁？
        self.wait(7)
        self.play(Write(Q2))
        #假如轮到乙开枪的时候三人都存活，乙应该打谁？
        self.wait(7)
        self.play(Write(Q3))
        #甲最先开枪，应该打谁？
        self.wait(7)
        self.play(FadeOut(Qlist))
        #我们先声明一个显然的事实，如果你在打某人，但打中的结果还不如没打中，那么干脆不打。
        self.wait(5)
        # Condition 1
        con1 = TexText("甲打中乙").set_color(BLACK).scale(1.5).to_edge(UP).shift(LEFT*FRAME_X_RADIUS/2)
        P1 = Tex("P(\\text{甲打中乙后存活})=0\%").set_color(BLACK).to_edge(LEFT)
        self.play(Write(con1))
        #第一种情况，假如甲打乙
        Beat("A","B")
        self.wait()
        #若打中，甲立刻被丙消灭，甲生还率0%
        Beat("C","A")
        self.play(Write(P1))
        self.wait()
        self.play(P1.animate.scale(.5).to_corner(DL),FadeOut(con1),FadeOut(cross_on_A),FadeOut(cross_on_B))
        self.wait()
        # Condition 2
        con2 = TexText("甲打中丙").set_color(BLACK).scale(1.5).to_edge(UP).shift(LEFT*FRAME_X_RADIUS/2)
        P2 = Tex("P(\\text{甲打中丙后存活})=","60\%\\times0","+","40\%\\times","(30\%\\times1+70\%\\times P)").set_color(BLACK).scale(.5).to_edge(LEFT)
        self.play(Write(con2))
        #第二种情况，假如甲打丙
        Beat("A","C")
        self.wait()
        self.play(Write(P2[0]))
        #若打中，甲生还的概率如下计算：
        self.wait(4)
        #首先如果被乙打中了，那么必死无疑
        Beat("B","A",fade_cross=True,animation=Write(P2[1]))
        self.wait()
        
        self.play(Write(P2[2]))
        self.wait()
        #接着再加上没有被乙打中的情况，于是我们得到了整体的P
        Beat("B","A",animation=Write(P2[3]),success=False)
        self.wait(3)
        self.play(Write(P2[4]))
        explain2 = TexText("$\\qquad$在下一轮中，甲有$30\%$的概率打中乙，那么存活概率是$30\%\\times1$，如果没有打中乙，那么就回到了本情况的初始局面，所以存活概率是$70\%\\times P$。因此，总的概率是$30\%\\times1+70\%\\times P$。").scale(.4).next_to(P2,DOWN).set_color(BLACK)
        #要注意这里没有被乙打中并不意味着一定能存活，
        #而是在下一轮中有30%*1+70%*P的概率存活，具体解释详见图中文字。
        self.wait(15)
        self.play(Write(explain2))
        self.wait(4)
        P2p = Tex("P(\\text{甲打中丙后存活})=","\\frac16","\\approx","16.7\%").set_color(BLACK).scale(.5).to_edge(LEFT)
        self.play(FadeOut(explain2),TransformMatchingTex(P2,P2p))
        #因此解得，P = 1/6 ≈ 16.7%
        self.wait(5)
        self.play(FadeOut(con2),FadeOut(cross_on_C),P2p.animate.next_to(P1,UP).align_to(P1,LEFT))
        self.wait()
        # Condition 3
        con3 = TexText("甲不打").set_color(BLACK).scale(1.5).to_edge(UP).shift(LEFT*FRAME_X_RADIUS/2)
        P31 = Tex("P_1","=","30\%\\times1","+","70\%\\times","(60\%\\times0+40\%\\times P_1)}").set_color(BLACK).scale(.5).to_edge(LEFT)
        self.play(Write(con3))
        #假如甲未打中任何人，乙肯定会打丙
        self.wait(5)
        #若打中（60%）
        Beat("B","C")
        self.wait()
        #则甲生还的概率P_1
        self.play(Write(P31[0:2]))
        self.wait()
        #如果甲打中了，那么成功存活
        Beat("A","B",animation=Write(P31[2]),fade_cross=True)
        self.wait()
        self.play(Write(P31[3]))
        self.wait()
        #再加上甲没有打中的情况，于是我们得到了整体的P_1
        Beat("A","B",animation=Write(P31[4]),success=False)
        self.wait(3)
        self.play(Write(P31[5]))
        explain3 = TexText("$\\qquad$在下一轮中，乙有$60\%$的概率打中甲，那么存活概率是$60\%\\times0$，如果没有打中甲，那么就回到了本情况的初始局面，所以存活概率是$40\%\\times P_1$。因此，总的概率是$60\%\\times0+40\%\\times P_1$。").scale(.4).next_to(P31,DOWN).align_to(explain2,LEFT).set_color(BLACK)
        #同样的甲没有打中并不意味着一定能存活，而是在下一轮中有60%*0+40%*P的概率存活，具体解释详见图中文字。
        self.wait(15)
        self.play(Write(explain3))
        self.wait(4)
        P31p = Tex("P_1","=","\\frac{5}{12}").scale(.5).to_edge(LEFT).set_color(BLACK)
        self.play(FadeOut(explain3),TransformMatchingTex(P31,P31p))
        self.wait(5)
        self.play(FadeOut(cross_on_C),P31p.animate.shift(UP))
        self.wait(2)
        P32 = Tex("P_2","=","30\%").scale(.5).set_color(BLACK).to_edge(LEFT)
        #若乙打丙未打中
        Beat("B","C",success=False)
        self.wait()
        #丙必定打中乙
        Beat("C","B")
        self.wait()
        #则甲生还的概率为30%（成王败寇）
        Beat("A","C",animation=Write(P32),fade_cross=True)
        self.wait(2)
        self.play(P32.animate.next_to(P31p))
        self.wait()
        P3 = Tex("P(\\text{甲放空后存活})=","60\%","P_1","+","40\%","P_2","=","37\%").scale(.5).set_color(BLACK).to_edge(LEFT)
        #通过对两种情况的合并，我们算出甲生还的概率为37%
        self.play(TransformMatchingTex(VGroup(P31p[0].copy(),P32[0].copy()),P3[:-2]))
        self.wait()
        self.play(Write(P3[-2:]))
        self.wait(5)
        P3p = Tex("P(\\text{甲放空后存活})=","37\%").scale(.5).set_color(BLACK).to_edge(LEFT)
        self.play(TransformMatchingTex(P3,P3p),FadeOut(P31p),FadeOut(P32))
        self.play(P3p.animate.next_to(P3,UP).align_to(P3,LEFT),P2p.animate.move_to(P3).to_edge(LEFT),P1.animate.next_to(P3,DOWN).align_to(P3,LEFT))
        #优于打中任何一个人，所以甲的最佳选择是放空枪。
        self.wait()
        self.play(FlashAround(P3p),FadeOut(P2p),FadeOut(P1),FadeOut(con3),FadeOut(cross_on_B),run_time=3)
        self.wait(3)
        P_B = Tex("P(\\text{丙此时存活})=70\%\\times40\%=28\%").scale(.5).to_edge(LEFT).set_color(BLACK)
        P_C = Tex("P(\\text{乙此时存活})=1-37\%-28\%=35\%").scale(.5).next_to(P_B,DOWN).to_edge(LEFT).set_color(BLACK)
        #经过简单的计算，丙在本情况存活的概率28%
        self.play(Write(P_B))
        self.wait(3)
        #用1减一减，得乙生还的概率为35%
        self.play(Write(P_C))
        self.wait(6)
        self.play(FadeOut(VGroup(P_B,P_C,P3p)))
        self.wait()
class Part3(Scene):
    def construct(self):
        title = TexText("拿硬币博弈").scale(2).to_edge(UP).set_color(BLACK)
        self.play(Write(title))
        self.wait(3)
        self.play(FadeOut(title))
# Part4
class Part4(Scene):
    def construct(self):
        title = TexText("硬币博弈").scale(2).to_edge(UP).set_color(BLACK)
        squ = Polygon(UP,RIGHT*2+DOWN,DOWN*3,LEFT*2+DOWN,stroke_width=5,stroke_color=BLACK)
        line1 = Line(RIGHT,LEFT+DOWN*2,stroke_width=3,stroke_color=BLACK)
        line2 = Line(LEFT,RIGHT+DOWN*2,stroke_width=3,stroke_color=BLACK)
        silent = VGroup(
            TexText("正面").move_to(np.array([-0.7,0.7,0])).rotate(45*DEGREES).set_color(RED),
            TexText("正面").move_to(np.array([0.7,0.7,0])).rotate(-45*DEGREES).set_color(RED),
        )
        complain = VGroup(
            TexText("反面").move_to(np.array([-1.7,-0.3,0])).rotate(45*DEGREES).set_color(GREEN),
            TexText("反面").move_to(np.array([1.7,-0.3,0])).rotate(-45*DEGREES).set_color(GREEN).insert_n_curves(20),
        )
        little1 = Line(UP,DOWN,stroke_width=1,stroke_color=BLACK)
        little2 = Line(LEFT,LEFT+DOWN*2,stroke_width=1,stroke_color=BLACK)
        little3 = Line(RIGHT,RIGHT+DOWN*2,stroke_width=1,stroke_color=BLACK)
        little4 = Line(DOWN,DOWN*3,stroke_width=1,stroke_color=BLACK)
        self.play(Write(title))
        self.wait(3)
        self.play(FadeOut(title))
        self.wait(2)
        self.play(ShowCreation(squ))
        self.wait()
        self.play(ShowCreation(line1),ShowCreation(line2),Write(silent[0]),Write(silent[1]),Write(complain[0]),Write(complain[1]))
        self.wait()
        SS = Group(
            plus(3).scale(0.1).next_to(little1,LEFT),
            plus(-3).scale(0.1).next_to(little1),
        )
        CS = Group(
            plus(-2).scale(0.1).next_to(little2,LEFT),
            plus(2).scale(0.1).next_to(little2),
        )
        SC = Group(
            plus(-2).scale(0.1).next_to(little3,LEFT),
            plus(2).scale(0.1).next_to(little3),
        )
        CC = Group(
            plus(1).scale(0.1).next_to(little4,LEFT),
            plus(-1).scale(0.1).next_to(little4),
        )
        self.play(FadeIn(SS[0]),FadeIn(SS[1]),ShowCreation(little1))
        self.wait(2)
        self.play(FadeIn(CS[0]),FadeIn(CS[1]),ShowCreation(little2))
        self.wait(2)
        self.play(FadeIn(SC[0]),FadeIn(SC[1]),ShowCreation(little3))
        self.wait(2)
        self.play(FadeIn(CC[0]),FadeIn(CC[1]),ShowCreation(little4))
        self.wait(5)
        # 如果乙选择坦白，你应该选择？（互动点）坦白
        self.play(CS.animate.set_opacity(0.5),SS.animate.set_opacity(0.5))
        self.wait(5)
        # 如果乙选择沉默，你应该选择？（互动点）坦白
        self.play(CS.animate.set_opacity(1),SS.animate.set_opacity(1),SC.animate.set_opacity(0.5),CC.animate.set_opacity(0.5))
        self.wait(5)
        # ababs
        self.play(SC.animate.set_opacity(1),CC.animate.set_opacity(1))
        self.wait(3)
        self.play(FadeOut(Group(*self.mobjects)))
        self.wait(40)
        self.wait(25)
        E = Tex("E","=","3pq","+","(1-p)(1-q)","-","2p(1-q)","-","2(1-p)q").shift(UP).set_color(BLACK)
        self.play(Write(E[0:2]))
        self.wait(2)
        self.play(Write(E[2]))
        self.wait(4)
        self.play(Write(E[3:5]))
        self.wait(4)
        self.play(Write(E[5:7]))
        self.wait(4)
        self.play(Write(E[7:]))
        self.wait(4)
        E2 = Tex("E","=","8pq","-","3p","-","3q","+","1",isolate=["p","q"]).insert_n_curves(30).set_color(BLACK).shift(UP)
        self.play(TransformMatchingTex(E,E2))
        self.wait(4)
        E3 = Tex("E","=","(","8q","-","3",")p","-","3q","+","1",isolate=["p","q"]).insert_n_curves(30).set_color(BLACK).shift(UP)
        self.play(TransformMatchingTex(E2,E3))
        self.wait(4)
        #互动点
        self.wait(5)
        E4 = Tex("E","=","(","8","\\times","\\frac38","-","3",")p","-","3","\\times","\\frac38","+","1",isolate=["p","q"]).set_color(BLACK).shift(UP)
        self.play(TransformMatchingTex(E3,E4,key_map={"q":"\\frac38"}))
        self.wait(5)
        E5 = Tex("E","=","-","\\frac18").set_color(BLACK).shift(UP)
        self.play(TransformMatchingTex(E4,E5))
        self.wait(5)
        self.play(TransformMatchingTex(E5,E3))
        self.wait(5)
        E6 = Tex("E","=","(","8p","-","3",")q","-","3p","+","1",isolate=["p","q"]).insert_n_curves(30).set_color(BLACK).shift(UP)
        self.play(TransformMatchingTex(E3,E6))
        self.wait(3)
        self.play(FadeOut(E6))
        self.wait()
        A = Tex("A","=","E(","p_0",",","q",")","=","E(","p_0",",","q_0",")").insert_n_curves(30).set_color(BLACK).shift(UP)
        B = Tex("B","=","E(","p",",","q_0",")","=","E(","p_0",",","q_0",")").insert_n_curves(30).set_color(BLACK)
        self.play(Write(A[:7]))
        self.wait(3)
        self.play(Write(B[:7]))
        self.wait(3)
        self.wait(5)
        self.play(TransformMatchingTex(A[2:7].copy(),A[7:],key_map={"q":"q_0"}))
        self.wait(5)
        self.play(TransformMatchingTex(B[2:7].copy(),B[7:],key_map={"p":"p_0"}))
        self.wait(3)
        AB = Tex("A","=","E(","p_0",",","q_0",")","=","B").insert_n_curves(30).set_color(BLACK).shift(UP*0.5)
        self.play(TransformMatchingTex(VGroup(*A,*B),AB))
        self.wait(60)

        
        